unit i18nManager;
{
  Internationalization-Manager

  HINT: Some other Units (e.g. MooViewer) use i18nManager. To compile them with
        internationalization support, just set the global $DEFINE "USE_I18N".
        These units use the global instance "i18nMgr" declared in this unit. It
        is recommended to use it in your projects as well instead of declaring
        an own instance.

  Last modified:  2004-10-29 by Christian Geyer


  Modification history:
    2005-07-25 koelzk:
                * added support for TControl.Hint
                * improved DoExtractControlInfo()
                * added IsIgnoredControl() for specifying component types,
                  which are ignored for translation
    2004-10-29: * added support for controls and standard user-defined text by
                  distinguishing beetween both internally
    2004-10-28: * added global variable i18nMgr, which is used by components
                  by default (e.g. MooViewer), when global switch USE_I18N is
                  set
                * added AddLanguageStrings methods
                * added method GetTranslationFormatted
    2004-08-13: * documentation comments

  Description:
    Iterates over given Forms/Win-Controls and translates them including its children controls.

  Usage example:
    1) Export the strings for editing

        i18nMgr:=tI18NManager.Create('Default');

        i18nMgr.ControlRegister(YourForm1);
        i18nMgr.ControlRegister(YourForm2);
        ...
        i18nMgr.ControlRegister(YourFormN);

        i18nMgr.ExportLanguageToFile('Default', YourFileName);
        i18nMgr.Free;

    2) Import a language file for translating the forms

        i18nMgr:=tI18NManager.Create;

        i18nMgr.ControlRegister(YourForm1);
        i18nMgr.ControlRegister(YourForm2);
        ...
        i18nMgr.ControlRegister(YourFormN);  //multiple language files can be used, for example if desired for every form a seperate language file

        i18nMgr.AddLanguageFile('English', MyEnglishLanguageFile);
        i18nMgr.SetLanguage('English');
        i18nMgr.PerformTranslate;

        i18nMgr.Free;


    3) Let the user specify the language

         i18nMgr.ShowSelectLanguageDialog;

}
interface

uses Classes, i18nLanguage, Contnrs;



type tI18NManager=class
       constructor Create(aDefaultLanguage: string); reintroduce;
       destructor Destroy; override;
     protected
       FCurrentLanguage: tI18NLanguage;
       FDefaultLanguage: tI18NLanguage;
       Languages: TStringList;
       RegisteredControls: TObjectList;
       DefaultLanguageStrippedControls: TStringList;
       function AddLanguage(Language: string): tI18NLanguage;
       procedure StripOffDefaultLanguageIfNeeded(Control: TComponent);
     public
       procedure AddLanguageFile(Language: string; FileName: string);
       procedure AddLanguageStrings(Language: string; Strings: TStringList); overload;
       procedure AddLanguageStrings(Language: string; Strings: array of string); overload;
       procedure ExportLanguageToFile(Language: string; FileName: string);

       procedure SetLanguage(Language: string; PerformTranslationNow: boolean);
       procedure PerformTranslation;

       procedure ControlRegister(Control: TComponent;
         PerformTranslationForThisControlNow: Boolean = false);
       procedure ControlUnRegister(Control: TComponent);
       procedure ControlTranslateSingle(Control: TComponent);

       function GetAvailableLanguagesAsCommaText: string;
       function ShowSelectLanguageDialog: string;

       function GetTranslation(UntranslatedIDString: string): string;
       function GetTranslationFormatted(UntranslatedIDString: string; StringParameters: array of const): string;
       function DefaultLanguageSaveToRegistry: boolean;
       function DefaultLanguageLoadFromRegistry: boolean;
       property CurrentLanguage: tI18NLanguage read FCurrentLanguage;
       property DefaultLanguage: tI18NLanguage read FDefaultLanguage;
     end;

var i18nMgr: tI18NManager;  //default manager instance for the libraries used!!!

implementation

uses i18nConfigForm, StringUtil, SysUtils, Registry, Windows;

{ tI18NManager }

constructor tI18NManager.Create(aDefaultLanguage: string);
begin
  inherited Create;
  Languages:=TStringList.Create;
  RegisteredControls := TObjectList.Create(False);
  FCurrentLanguage := AddLanguage(aDefaultLanguage);
  FDefaultLanguage := FCurrentLanguage;
  DefaultLanguageStrippedControls := TStringList.Create;
end;

destructor tI18NManager.Destroy;
begin
  DefaultLanguageStrippedControls.Free;
  RegisteredControls.Free;
  Languages.Free;
  inherited;
end;

procedure tI18NManager.AddLanguageFile(Language, FileName: string);
var SL: TStringList;
begin
  SL:=TStringList.Create;
  SL.LoadFromFile(FileName);
  AddLanguageStrings(Language, SL);
  SL.Free;
end;

procedure tI18NManager.AddLanguageStrings(Language: string; Strings: TStringList);
var index: integer;
begin
  index:=Languages.IndexOf(Language);
  if index>-1
    then ti18nLanguage(Languages.Objects[index]).AddLanguageStrings(Strings)
    else AddLanguage(Language).AddLanguageStrings(Strings);
end;

procedure tI18NManager.AddLanguageStrings(Language: string; Strings: array of string);
var SL: TStringList;
begin
  SL:=StrArrayToStringList(Strings);
  AddLanguageStrings(Language, SL);
  SL.Free;
end;

procedure tI18NManager.ControlRegister(Control: TComponent;
  PerformTranslationForThisControlNow: Boolean = false);
begin
  RegisteredControls.Add(Control);
  StripOffDefaultLanguageIfNeeded(Control);
  if PerformTranslationForThisControlNow then
    ControlTranslateSingle(Control);
end;

procedure tI18NManager.ControlUnRegister(Control: TComponent);
begin
  RegisteredControls.Remove(Control);
end;

procedure tI18NManager.ControlTranslateSingle(Control: TComponent);
begin
  StripOffDefaultLanguageIfNeeded(Control);
  FCurrentLanguage.TranslateControl(Control);
end;









procedure tI18NManager.ExportLanguageToFile(Language, FileName: string);
var index: integer;
begin
  index:=Languages.IndexOf(Language);
  if index>-1 then
    tI18NLanguage(Languages.Objects[index]).SaveToLanguageFile(FileName);
end;

procedure tI18NManager.PerformTranslation;
var i: integer;
begin
  for i:=0 to RegisteredControls.Count-1 do
    FCurrentLanguage.TranslateControl(tComponent(RegisteredControls[i]));
end;

procedure tI18NManager.SetLanguage(Language: string; PerformTranslationNow: boolean);
var index: integer;
begin
  index:=Languages.IndexOf(Language);
  if index>-1
    then FCurrentLanguage:=ti18nLanguage(Languages.Objects[index])
    else FCurrentLanguage:=AddLanguage(Language);
  if PerformTranslationNow=true then PerformTranslation;
end;



function tI18NManager.AddLanguage(Language: string): tI18NLanguage;
begin
  result:=tI18NLanguage.Create;
  result.Locale:=Language;
  Languages.AddObject(Language, result);
end;

procedure tI18NManager.StripOffDefaultLanguageIfNeeded(Control: TComponent);
begin
  if DefaultLanguageStrippedControls.IndexOf(FDefaultLanguage.GetHierarchyString(Control))<0 then
  begin  //Default language has not been stripped off this control, yet. Do it now!
    FDefaultLanguage.ExportControl(Control);
    DefaultLanguageStrippedControls.Add(FDefaultLanguage.GetHierarchyString(Control));
  end;
end;

function tI18NManager.GetAvailableLanguagesAsCommaText: string;
begin
  result := Languages.CommaText;
end;

function tI18NManager.ShowSelectLanguageDialog: string;
//var ld: Tfrmi18nConfig;
begin
{
  ld:=Tfrmi18nConfig.Create(nil);
  ControlRegister(ld, true);
  ld.LanguagesAsCommaText:=GetAvailableLanguagesAsCommaText;
  ld.SelectedLanguage:=DefaultLanguage.Locale;
  ld.Parenti18nManager:=Self;
  ld.ShowModal;
  result:=ld.SelectedLanguage;
  ControlUnRegister(ld);
  ld.Free;}
end;

function tI18NManager.GetTranslation(UntranslatedIDString: string): string;
begin
  result:=FCurrentLanguage.GetTranslation(UntranslatedIDString);
  if result='' then FDefaultLanguage.GetTranslation(UntranslatedIDString);
end;

function tI18NManager.GetTranslationFormatted(UntranslatedIDString: string; StringParameters: array of const): string;
begin
  result:=Format(FCurrentLanguage.GetTranslation(UntranslatedIDString), StringParameters);
  if result='' then Format(FDefaultLanguage.GetTranslation(UntranslatedIDString), StringParameters);
end;


function tI18NManager.DefaultLanguageSaveToRegistry: boolean;
var Reg: tRegistry;
begin
  result:=true;
  try
    Reg:=TRegistry.Create;
    try
      Reg.RootKey:=HKEY_CURRENT_USER;
      if Reg.OpenKey('\Software\Crispy Cow Entertainment', True) then
      begin
        Reg.WriteString('i18nDefaultLanguage', FCurrentLanguage.Locale);
        Reg.CloseKey;
      end;
    finally
      Reg.Free;
    end;
  except
    result:=false;
  end;
end;

function tI18NManager.DefaultLanguageLoadFromRegistry: boolean;
var Reg: tRegistry;
    Language: string;
begin
  result:=true;
  try
    Reg:=TRegistry.Create;
    try
      Reg.RootKey:=HKEY_CURRENT_USER;
      if Reg.OpenKey('\Software\Crispy Cow Entertainment', True) then
      begin
        Language:=Reg.ReadString('i18nDefaultLanguage');
        if Language<>'' then SetLanguage(Language, true);
        Reg.CloseKey;
      end;
    finally
      Reg.Free;
    end;
  except
    result:=false;
  end;
end;

end.
